feat: rich chat notifications with inline transcript, reply, and Send Cash#416
Open
raulriera wants to merge 19 commits into
Open
feat: rich chat notifications with inline transcript, reply, and Send Cash#416raulriera wants to merge 19 commits into
raulriera wants to merge 19 commits into
Conversation
…estions Index DM chats into CoreSpotlight (with avatars) so they're searchable and open on tap, donate open chats as Siri Suggestions/Handoff, and add a Send Cash app shortcut that opens the send flow for a contact. Spotlight taps and the shortcut route through the app's existing deep-link navigation.
- PushController registers the CHAT_MESSAGE category on init with
Reply (text-input) and Send Cash (.foreground) actions
- didReceive posts flipcash://chat/{id}/send to the deep-link pipeline
when the Send Cash action is tapped, decoding the chat ID from the
push payload navigation
- Route.Path gains .chatSendCash(ConversationID); /chat/{id}/send
parses to it while /chat/{id} stays .chat
- DeepLinkController handles .chatSendCash: resolves the conversation
counterpart via ChatNotificationRouter and navigates to .sendAmount
when canSend is true
- ScanViewModel.canScanQR updated for exhaustive switch
- RouteTests gains two cases verifying /chat/{id}/send and /chat/{id}
parse correctly
… migration Route the owner account (.currentUserAccount) through a runtime-derived shared keychain access group so a notification extension can authenticate. Reads fall back to the legacy groupless location and a one-time migration copies the existing item into the shared group, guaranteeing no logout for existing users on upgrade.
…cation previews Public FlipcashUI extension that maps [ConversationMessage] to the last 3 ChatItems (sorted chronologically, oldest-first) — usable by the notification content extension which cannot link the main app target.
Bridges the shared keychain access group to the notification content extension, which has no access to the main app's private group.
Notification content extension (CHAT_MESSAGE category) linking FlipcashCore + FlipcashUI, embedded in the app, with the shared keychain-access-group entitlement. Stub view controller; content rendering follows.
- OwnerKeyStore.loadOwnerAccount() returns both KeyPair and UserID; loadOwnerKeyPair() delegates to it - NotificationPayload.chatConversationID(from:) extracts ConversationID without requiring FlipcashAPI import in the extension - NotificationViewController fetches last 3 messages on push receipt, renders ChatMessageCell bubbles via UICollectionView + compositional list layout, handles inline reply (sendMessage + append bubble) and Send Cash action forwarding - Bumped NotificationContent deployment target to 18.0 (matches FlipcashCore requirement)
Track the status label and remove the prior one before showing a new one; clear it when content loads. A fetch error followed by a send error no longer stacks two overlapping labels.
…leak, analytics gate, decode path C1: Keychain.set with an accessGroup now inserts .accessible(.afterFirstUnlock) so the shared owner-account item is readable by the notification extension while the device is locked. The resolveTeamPrefix probe item gets the same accessibility so team-prefix resolution also works in that context. I1: NotificationViewController now holds a single lazy ChatNotificationClient instead of creating one in each didReceive call, preventing NIO event-loop-group leaks. ChatNotificationClient gains @unchecked Sendable to satisfy Swift 6 actor-isolation checks. Minor: Analytics.deeplinkRouted for .chatSendCash now fires only when the route proceeds (inside the canSend guard). PushController.didReceive now uses NotificationPayload.chatConversationID instead of inline decode.
- Link UserNotificationsUI.framework so the content extension actually loads (it was being killed at launch: missing extension-point framework) - Force dark mode + paint the chat background so the white bubbles are visible - Render cash messages via ChatCashCardCell with currency + flag, not blank bubbles - Match the real chat's bubble spacing and width - Poll while expanded so the counterparty's new messages appear live
Open the chat as the root sheet then stack Send Cash on top (present(.conversation) + presentNested(.sendAmount)), matching #402, so it always lands back in the chat. Repoint callers to main's NotificationPayload.chatID(_:) (drop the duplicate helper) and update the preview switch for main's ChatItem (no .receipt).
Add present(_:animated:) to AppRouter; the notification Send Cash deeplink and the App Intents send now mount the chat instantly (animated: false) and animate only the Send Cash amount sheet on top, so it opens directly with the chat already behind it instead of sliding the chat in first.
The notification Send Cash deeplink and the App Intents send now present .sendAmount as a root sheet — one animation, no chat slide-up behind it. Render .sendAmount at the ScanScreen root (was EmptyView, nested-only) and expose SendAmountSheetRoot. Reverts the no-op present(animated:) (disablesAnimations does not suppress a SwiftUI sheet's presentation animation).
Embed ChatViewController so the expanded notification sizes to its content, scrolls, and renders every cell (including the cash card) like the in-app chat. Hide the default notification content so the message isn't shown twice, and match the extension version to the app so iOS loads the extension.
Resolve mint metadata over the network from the extension (lean CurrencyService on the payments host, cached per mint) and render it without the diff sliding it in. Plus rich-notification cleanup: dedupe the send-target construction, the keychain test helper, and the transcript reload path; tidy comments.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a rich notification for incoming chat messages. Expanding a chat push now shows the recent conversation inline — message bubbles and cash cards that display the token's name and icon — with inline reply and a Send Cash action that opens the amount sheet for the sender. The notification extension runs without the full app session: the owner key is shared into a keychain access group, and chat messages and token metadata are fetched over the network, so the extension needs no database.
Stacked on #395 (App Intents) — that commit appears in this diff until #395 merges, after which this branch rebases down to just the notification changes.
Test plan